#ifndef LECTEURPHRASEAVECARBRE_H_
#define LECTEURPHRASEAVECARBRE_H_

#include "Symbole.h"
#include "LecteurSymbole.h"
#include "TableSymboles.h"
#include "Arbre.h"
#include <vector>
#include <exception>

#include <string>
using namespace std;

class Exception1 {
public:

    Exception1(string mess) {
        message=mess;
    };
    string message;
};

class LecteurPhraseAvecArbre {
public:

    /*! \fn LecteurPhraseAvecArbre(string nomFich)
        \brief Construit un lecteur de phrase pour interpreter le programme dans le fichier nomFich
        \param nomFich - le nom du fichier à interpreter
     */
    LecteurPhraseAvecArbre(string nomFich);

    /*! \fn analyse()
        \brief Si le contenu du fichier est conforme à la grammaire, cette méthode se termine et affiche "Syntaxe correcte"
     la table des symboles (ts) et l'arbre abstrait (arbre) auront été construits. Sinon le programme est interrompu
     */
    void analyse();

    /*! \fn getTs()
        \brief Retourne la table des symboles ts
     */
    inline TableSymboles getTs() {
        return ts;
    } // accesseur	

    /*! \fn getArbre()
        \brief Retourne l'arbre arbre
     */
    inline Noeud* getArbre() {
        return arbre;
    } // accesseur


private:

    /*! \var LecteurSymbole ls 
        \brief Le lecteur de symbole utilisé pour analyser le fichier
     */
    LecteurSymbole ls;

    /*! \var TableSymboles ts 
        \brief La table des symboles valués
     */
    TableSymboles ts;

    /*! \var Noeud* arbre 
        \brief L'arbre abstrait
     */
    Noeud* arbre;

    // implémentation de la grammaire
    /*! \fn programme()
        \brief <programme> ::= debut <seqInst> fin FIN_FICHIER
     */
    Noeud* programme();

    /*! \fn seqInst()
        \brief <seqInst> ::= <inst> ; { <inst> ; }
        \return Noeud*, partie de l'arbre
     */
    Noeud* seqInst();

    /*! \fn inst()
        \brief <inst> ::= <affectation>
        \return Noeud*, partie de l'arbre
     */
    Noeud* inst();

    /*! \fn affectation()
        \brief <affectation> ::= <variable> = <expression>
        \return Noeud*, partie de l'arbre
     */
    Noeud* affectation();

    /*! \fn expression()
        \brief <expression> ::= <facteur> { <opBinaire> <facteur> }
        \return Noeud*, partie de l'arbre
     */
    Noeud* expression(); //  <expression> ::= <facteur> { <opBinaire> <facteur> }

    /*! \fn facteur()
        \brief <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
        \return Noeud*, partie de l'arbre
     */
    Noeud* facteur(); //     <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

    /*! \fn opBinaire()
        \brief <opBinaire> ::= + | - | *  | / 
        \return Noeud*, partie de l'arbre
     */
    Symbole opBinaire();

    /*! \fn terme()
        \brief <terme> ::= { <opMult> <facteur> }
        \return Noeud*, partie de l'arbre
     */
    Noeud * terme();

    /*! \fn opAdd()
        \brief <opAdd> ::= + | -
        \return Symbole de l'opération
     */
    Symbole opAdd();

    /*! \fn opMult()
        \brief <opMult> ::= * | /
        \return Symbole de l'opération
     */
    Symbole opMult();

    /*! \fn expBool()
        \brief <expBool> ::= <expBoolEt>
        \return Noeud*, partie de l'arbre
     */
    Noeud * expBool();

    /*! \fn relation()
        \brief <relation>::= <expression> { <opRel> <expression> }
        \return Noeud*, partie de l'arbre
     */
    Noeud * relation();

    /*! \fn opRel()
        \brief <opRel> ::= == | != | > | >= | < | <=
        \return Symbole, l'opérateur
     */
    Symbole opRel();

    /*! \fn opUnaire()
        \brief <opUnaire> ::= - | non
        \return Noeud*, partie de l'arbre
     */
    Noeud * opUnaire();

    /*! \fn instSi()
        \brief <instSi>  ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> [ sinon <seqInst> ] finsi 
        \return Noeud*, partie de l'arbre
     */
    Noeud * instSi();

    /*! \fn instTq()
        \brief <instTq>  ::= tantque ( <expBool> ) <seqInst> fintantque
        \return Noeud*, partie de l'arbre
     */
    Noeud * instTq();

    /*! \fn instRepeter()
        \brief <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> ) 
        \return Noeud*, partie de l'arbre
     */
    Noeud * instRepeter();

    /*! \fn instPour()
        \brief <instPour> ::= pour ( <affectation> ; <expBool> ; <affectation> ) <seqInst> finpour
        \return Noeud*, partie de l'arbre
     */
    Noeud * instPour();

    /*! \fn instLire()
        \brief <instLire> ::= lire ( <VARIABLE> )
        \return Noeud*, partie de l'arbre
     */
    Noeud * instLire();

    /*! \fn instEcrire()
        \brief <instEcrire> ::= ecrire ( <CHAINE> | <expression> )
        \return Noeud*, partie de l'arbre
     */
    Noeud * instEcrire();

    /*! \fn expBoolEt()
        \brief <expBoolEt> ::= <expBoolOu> { et <expBoolOu> }
        \return Noeud*, partie de l'arbre
     */
    Noeud * expBoolEt();

    /*! \fn expBoolOu()
        \brief <expBoolOu> ::= <Relation> { ou <Relation> }
        \return Noeud*, partie de l'arbre
     */
    Noeud * expBoolOu();

    /*! \fn choix()
        \brief <choix> ::= <choix>
        \return Noeud*, partie de l'arbre
     */    
    Noeud * choix();
    
    // outils pour se simplifier l'analyse syntaxique
    /*! \fn testerSymCour(string ch)
        \brief si symbole courant != ch, erreur : on arrete le programme, sinon rien
     */
    void testerSymCour(string ch);

    /*! \fn sauterSymCour(string ch)
        \brief si symbole courant == ch, on passe au symbole suivant, sinon erreur : on arrete
     */
    void sauterSymCour(string ch);

    /*! \fn erreur(string mess)
        \brief affiche les message d'erreur mess et arrete le programme
     */
    void erreur(string mess);
};

#endif /* LECTEURPHRASEAVECARBRE_H_ */
